/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.heron-language.com
    Translates an AST generated from Heron code into an s-expression form
		called "llscheme"
*/

#ifndef HERON_TO_LLSCHEME_HPP
#define HERON_TO_LLSCHEME_HPP

#include <string>
#include <vector>
#include <map>
#include <exception>
#include <iostream>

#include "cvml.hpp"

namespace heron_to_lls
{
    using namespace heron_ast;
 
	using lls::SExpr;

    class HeronToLLS
    {

        // typedefs
        typedef AstNodeList<SimpleExpr> ExprList;
        
    public:

        HeronToLLS()   
        {
        }

		~HeronToLLS() 
		{
		}

        bool ExprMatches(ExprList& exprlist, int& cur, char* x) {
            if (cur >= exprlist.Count()) 
                return false;
            std::string s(exprlist.At(cur)->expr->ToString());
            if (s == x) {
                ++cur;
                return true;
            }
            return false;
        }

        template<typename T>
        bool ExprIsTypeNoAdvance(ExprList& exprlist, int cur) {
            if (cur >= exprlist.Count())
                return false;
            return exprlist.At(cur)->expr->template TypeMatches<T>();
        }
		
        SExpr* ConvertLiteral(ExprList& exprlist, int& cur) {
            if (cur >= exprlist.Count())
                return NULL;
            Literal* lit = exprlist.At(cur++)->expr->CastTo<Literal>();

            Assert(lit != NULL, "expected a literal");

            if (lit->value->TypeMatches<BinNumber>()) {
				Error("Binary numbers not yet supported");
			}
            else if (lit->value->TypeMatches<HexNumber>()) {
				Error("Hexadecimal numbers not yet supported");
            }
            else if (lit->value->TypeMatches<DecNumber>()) {
				return new lls::PLiteral<int>(StrToInt(lit->value->ToString()));
            }
            else if (lit->value->TypeMatches<CharLiteral>()) {
				return new lls::PLiteral<char>(StrToChar(lit->value->ToString()));
            }
            else if (lit->value->TypeMatches<StringLiteral>()) {
				String s = lit->value->ToString();
				return new lls::PLiteral<String>(s.substr(1, s.size() - 2));
            }

			Error("unrecognized literal type");
			return NULL;
        }

        SExpr* ConvertNewExpr(ExprList& exprlist, int& cur) {
            if (cur >= exprlist.Count())
                return NULL;
            AstNode* expr = exprlist.At(cur++)->expr;
            NewExpr* newexpr = dynamic_cast<NewExpr*>(expr);
			NonNull<SExpr> r = new lls::New();
			r->AddChild(ConvertType(newexpr->type));
			r->AddChild(ConvertArgs(newexpr->args));
			return r;
        }

        SExpr* ConvertName(ExprList& exprlist, int& cur) {
            if (cur >= exprlist.Count()) 
                return NULL;
            SimpleExpr* name = exprlist.At(cur++);
            std::string sname = name->expr->ToString();            
			return new lls::Get(sname);
        }

        SExpr* ConvertParanthesizedExpr(ExprList& exprlist, int& cur) {
            if (cur >= exprlist.Count()) 
                return NULL;
            AstNode* expr = exprlist.At(cur)->expr;
			++cur;
            ParanthesizedExpr* paranexpr = dynamic_cast<ParanthesizedExpr*>(expr);
            NonNull<SExpr> r = ConvertParanthesizedExpr(paranexpr);
			return r;
        }

        SExpr* ConvertParanthesizedExpr(NonNull<ParanthesizedExpr> expr) {
			if (expr->subexprs.Count() != 0) {
				Error("expected precisely one sub-expression between paranthesis");
			}
			return ConvertExpr(expr->subexprs.At(0));
        }

        SExpr* ConvertPrimaryExpr(ExprList& exprlist, int& cur) {
			if (cur >= exprlist.Count()) {
                return NULL;
			}
			else if (ExprIsTypeNoAdvance<Name>(exprlist, cur)) {
                return ConvertName(exprlist, cur);
            }
            else if (ExprIsTypeNoAdvance<Literal>(exprlist, cur)) {
                return ConvertLiteral(exprlist, cur);
            }
            else if (ExprIsTypeNoAdvance<ParanthesizedExpr>(exprlist, cur)) {
                return ConvertParanthesizedExpr(exprlist, cur);
            }
            else if (ExprIsTypeNoAdvance<NewExpr>(exprlist, cur)) {
                return ConvertNewExpr(exprlist, cur);
            }
			else {
				// TODO: I am not sure that this is really an error. Can't remember.
				Error("unrecognized primary expression");
				return NULL;
			}
        }

		SExpr* ConvertArgs(NonNull<ParanthesizedExpr> args) {			
			NonNull<lls::Args> r = new lls::Args();
			for (int i=0; i < args->subexprs.Count(); ++i) {
				NonNull<SExpr> arg = ConvertExpr(args->subexprs.At(i));
				r->AddChild(arg);
			}
			return r;
		}

        SExpr* ConvertPostfixExpr(ExprList& exprlist, int& cur) {
            int save = cur;
            
            NonNull<SExpr> r = ConvertPrimaryExpr(exprlist, cur);                        

            while (true) { 
                if (cur >= exprlist.Count()) 
                    return r;
                AstNode* expr = exprlist.At(cur)->expr;

                if (expr->TypeMatches<ParanthesizedExpr>()) {
                    cur++;
                    ParanthesizedExpr* paran  = dynamic_cast<ParanthesizedExpr*>(expr);
                    
					SExpr* tmp = new lls::Apply();
					tmp->AddChild(r);
					r = tmp;
					r->AddChild(ConvertArgs(paran));
                }
                else if (expr->TypeMatches<BracketedExpr>()) {
                    cur++;
                    BracketedExpr* bexpr = dynamic_cast<BracketedExpr*>(expr);
					SExpr* tmp = new lls::GetAt();
					tmp->AddChild(r);
					r = tmp;
					r->AddChild(ConvertExpr(bexpr->expr));
                }
                else if (ExprMatches(exprlist, cur, ".")) {
                    if (cur >= exprlist.Count() || !exprlist.At(cur)->expr->TypeMatches<Name>()) {
                        Error("Expected a name expression");
                    }
                    AstNode* expr = exprlist.At(cur);
					++cur;
                    std::string s = expr->ToString();
                    SExpr* tmp = new lls::GetField();
					tmp->AddChild(r);
					tmp->AddChild(new lls::Name(s));
					r = tmp;
                }
				else {
					return r;
                }
            }                
        }        

        SExpr* ConvertUnaryExpr(ExprList& exprlist, int& cur) {
            if (ExprMatches(exprlist, cur, "-")) {
                NonNull<SExpr> r = new lls::Primitive(lls::prim_neg);
				r->AddChild(ConvertPostfixExpr(exprlist, cur));
				return r;
            }
            else {
                return ConvertPostfixExpr(exprlist, cur);
            }
        }

        SExpr* ConvertMulExpr(ExprList& exprlist, int& cur) {
            NonNull<SExpr> r = ConvertUnaryExpr(exprlist, cur);
            while (true) {
                if (ExprMatches(exprlist, cur, "*")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_mul);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertUnaryExpr(exprlist, cur));
                }
                else if (ExprMatches(exprlist, cur, "/")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_div);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertUnaryExpr(exprlist, cur));
                }
                else if (ExprMatches(exprlist, cur, "%")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_mod);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertUnaryExpr(exprlist, cur));
                }
                else {
                    return r;
                }
            }
        }

        SExpr* ConvertAddExpr(ExprList& exprlist, int& cur) {
            NonNull<SExpr> r = ConvertMulExpr(exprlist, cur);
            while (true) {
                if (ExprMatches(exprlist, cur, "+")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_add);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertMulExpr(exprlist, cur));
                }
                else if (ExprMatches(exprlist, cur, "-")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_sub);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertMulExpr(exprlist, cur));
                }
                else {
                    return r;
                }
            }
        }

        SExpr* ConvertRelExpr(ExprList& exprlist, int& cur) {
            NonNull<SExpr> r = ConvertAddExpr(exprlist, cur);
            while (true) {
                if (ExprMatches(exprlist, cur, ">")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_gt);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertAddExpr(exprlist, cur));
                }
                else if (ExprMatches(exprlist, cur, ">=")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_gteq);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertAddExpr(exprlist, cur));
                }
                else if (ExprMatches(exprlist, cur, "<")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_lt);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertAddExpr(exprlist, cur));
                }
                else if (ExprMatches(exprlist, cur, "<=")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_lteq);
					tmp->AddChild(r); 
					r = tmp;
					r->AddChild(ConvertAddExpr(exprlist, cur));
                }
                else {
                    return r;
                }
            }
        }

        SExpr* ConvertEqExpr(ExprList& exprlist, int& cur) {
            NonNull<SExpr> r = ConvertRelExpr(exprlist, cur);
            while (true) {
                if (ExprMatches(exprlist, cur, "==")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_eq); 
					tmp->AddChild(r);
					r = tmp;
					r->AddChild(ConvertRelExpr(exprlist, cur));
                }
                else if (ExprMatches(exprlist, cur, "!=")) {
                    SExpr* tmp = new lls::Primitive(lls::prim_neq); 
					tmp->AddChild(r);
					r = tmp;
					r->AddChild(ConvertRelExpr(exprlist, cur));
                }
                else {
                    return r;
                }
            }
        }

        SExpr* ConvertLogXOrExpr(ExprList& exprlist, int& cur) {
            NonNull<SExpr> r = ConvertEqExpr(exprlist, cur);
            while (ExprMatches(exprlist, cur, "^^")) {
				SExpr* tmp = new lls::Primitive(lls::prim_xor);
				tmp->AddChild(r);
                r = tmp;
				r->AddChild(ConvertEqExpr(exprlist, cur));
            }
			return r;
        }

        SExpr* ConvertLogAndExpr(ExprList& exprlist, int& cur) {
            NonNull<SExpr> r = ConvertLogXOrExpr(exprlist, cur);
            while (ExprMatches(exprlist, cur, "&&")) {
				SExpr* tmp = new lls::Primitive(lls::prim_and);
				tmp->AddChild(r);
				r = tmp;
				r->AddChild(ConvertLogXOrExpr(exprlist, cur));
            }
			return r;
        }

        SExpr* ConvertLogOrExpr(ExprList& exprlist, int& cur) {
            NonNull<SExpr> r = ConvertLogAndExpr(exprlist, cur);            
			while (ExprMatches(exprlist, cur, "||")) {
				SExpr* tmp = new lls::Primitive(lls::prim_or);
				tmp->AddChild(r);
				r = tmp;
                r->AddChild(ConvertLogAndExpr(exprlist, cur));
            }
			return r;
        }

        SExpr* ConvertCondExpr(ExprList& exprlist, int& cur) {            
            NonNull<SExpr> r = ConvertLogOrExpr(exprlist, cur);            
			while (ExprMatches(exprlist, cur, "?")) {
				SExpr* tmp = new lls::Primitive(lls::prim_cond);				
				tmp->AddChild(r);
				r = tmp; 
                r->AddChild(ConvertLogOrExpr(exprlist, cur));
				if (ExprMatches(exprlist, cur, ":")) {
                    r->AddChild(ConvertLogOrExpr(exprlist, cur));
                }
                else {
                    Error("Expected alternative value");
                }
            }
			return r;
        }

		SExpr* MakeAssignment(SExpr* lvalue, SExpr* rvalue) {
			if (lvalue->Is<lls::Get>()) {
				lls::Get* tmp = lvalue->As<lls::Get>();
				lls::Set* r = new lls::Set();
				r->AddChild(tmp->GetChild(0)->Clone());
				r->AddChild(rvalue);
				delete tmp;
				return r;
			}
			else if (lvalue->Is<lls::GetField>()) {
				lls::GetField* tmp = lvalue->As<lls::GetField>();
				lls::SetField* r = new lls::SetField();
				r->AddChild(tmp->GetChild(0)->Clone());
				r->AddChild(tmp->GetChild(1)->Clone());
				r->AddChild(rvalue);
				delete tmp;
				return r;
			}
			else if (lvalue->Is<lls::GetAt>()) {
				lls::GetAt* tmp = lvalue->As<lls::GetAt>();
				lls::SetAt* r = new lls::SetAt();
				r->AddChild(tmp->GetChild(0)->Clone());
				r->AddChild(tmp->GetChild(1)->Clone());
				r->AddChild(rvalue);
				delete tmp;
				return r;
			}
			else {
				Error(String("Can not use ") + lvalue->Label() + " as lvalue");
				return NULL;
			}
		}

		SExpr* ConvertAssExpr(ExprList& exprlist, int& cur) {
            int save = cur;
			NonNull<SExpr> r = ConvertUnaryExpr(exprlist, cur);
			if (r == NULL) {
				return r;
			}
			else if (cur >= exprlist.Count()) {
				return r;
			}
			else if (ExprMatches(exprlist, cur, "=")) {
				return MakeAssignment(r, ConvertCondExpr(exprlist, cur));
			}
			else if (ExprMatches(exprlist, cur, "+=")) {
				return MakeAssignment(r, 
					new lls::Primitive(lls::prim_add, r->Clone(), ConvertCondExpr(exprlist, cur)));
			}
			// TODO: handle the other assignment operators
			else {
				cur = save;
				delete r;
				return ConvertCondExpr(exprlist, cur);
			}
		}

        SExpr* ConvertExpr(ExprList& x, int& cur) {
            return ConvertAssExpr(x, cur);
        }

        SExpr* ConvertExpr(NonNull<Expr> x) {
			/*
			TODO: eventually support compound expressions
			NonNull<SExpr> r = new lls::CompoundExpr();
			int cur = 0;
            while (cur < x->exprs.Count()) {
                r->AddChild(ConvertExpr(x->exprs, cur));
            }
			return r;
			*/
			int cur = 0;
			try {
				NonNull<SExpr> r = ConvertExpr(x->exprs, cur);
				return r;
			}
			catch (...) {
				printf("failed to convert expression into LLScheme: '%s'\n", x->ToString().c_str());
				throw;
			}
        }

		SExpr* ConvertExprStatement(NonNull<ExprStatement> x) {
			return ConvertExpr(x->expr);
        }

		SExpr* ConvertImportStatement(NonNull<ImportStatement> x) {
			Error("Not implemented");
			return NULL;

			/*
			TODO: I need to have a global class path folder. 
			So that I can find a module. Or alternatively
			I need to load all files.

			lls::Import* r = new lls::Import();
			Stri	ng sModuleName = x->name->ToString();
			HeronAst ast(sModuleName.c_str());			
			Module* mod = dynamic_cast<Module*>(ast.root->program_or_module);
			if (mod == NULL) 
				Error("Can only import modules");
			r->AddChild(ConvertModule(mod));
			return r;
			*/
		}

		lls::Return* ConvertReturnStatement(NonNull<ReturnStatement> x) {
			lls::Return* r = new lls::Return();
            r->AddChild(ConvertExpr(x->expr));
			return r;
        }

		lls::While* ConvertWhileStatement(NonNull<WhileStatement> x) {
			lls::While* r = new lls::While();
			r->AddChild(ConvertExpr(x->cond));
			r->AddChild(ConvertStatement(x->body));
			return r;
        }

		lls::For* ConvertForStatement(NonNull<ForStatement> x) 
        {
			lls::For* r = new lls::For();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertType(x->type));
			r->AddChild(ConvertExpr(x->init));
			r->AddChild(ConvertExpr(x->inv));
			r->AddChild(ConvertExpr(x->iter));
			r->AddChild(ConvertStatement(x->body));
			return r;
        }

		lls::ForEach* ConvertForEachStatement(NonNull<ForEachStatement> x) {
			lls::ForEach* r = new lls::ForEach();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertType(x->type));
			r->AddChild(ConvertExpr(x->coll));
			r->AddChild(ConvertStatement(x->body));
			return r;
        }

		lls::If* ConvertIfStatement(NonNull<IfStatement> x) {
			lls::If* r = new lls::If(); 
			r->AddChild(ConvertExpr(x->cond));
			r->AddChild(ConvertStatement(x->body));
			if (x->alternative != NULL) {
				r->AddChild(ConvertStatement(x->alternative));
			}
			else {
				r->AddChild(new lls::NoOp());
			}
			return r;
        }

		String GetBasicType(ConstString s) {
			return SubStrToChar(s, '<');
		}

		SExpr* GenerateDefaultExpr(TypeExpr* x) {
			if (x == NULL) {
				return new lls::Primitive(lls::prim_null);
			}
			else if (x->ToString() == "Int") {
				return new lls::PLiteral<int>(0);
			}
			else if (x->ToString() == "Bool") {
				return new lls::PLiteral<bool>(false);
			}
			else if (x->ToString() == "Char") {
				return new lls::PLiteral<char>('\0');
			}
			else if (x->ToString() == "Float") {
				return new lls::PLiteral<double>(0.0);
			}
			else if (x->ToString() == "String") {
				return new lls::PLiteral<String>("");
			}
			else if (x->ToString() == "List" || GetBasicType(x->ToString()) == "Array") {
				return new lls::Primitive(lls::prim_nil);
			}
			else {
				Error("unhandled literal type: " + x->ToString());
				return NULL;
			}
		}

		lls::Var* ConvertVarDecl(NonNull<VarDecl> x) {
			lls::Var* r = new lls::Var();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertType(x->type));
			if (x->init != NULL) 
				r->AddChild(ConvertExpr(x->init));
			else 
				r->AddChild(GenerateDefaultExpr(x->type));
			return r;
		}

		SExpr* ConvertStatement(NonNull<Statement> x) {
			AstNode* child = x->statement;			
			if (child->TypeMatches<ForStatement>()) {					             
				return ConvertForStatement(dynamic_cast<ForStatement*>(child));
			}
			else if (child->TypeMatches<ForEachStatement>()) {
				return ConvertForEachStatement(dynamic_cast<ForEachStatement*>(child));
			}
			else if (x->statement->TypeMatches<CodeBlock>()) {
                return ConvertCodeBlock(dynamic_cast<CodeBlock*>(child));
			}
			else if (x->statement->TypeMatches<VarDecl>()) {		
                return ConvertVarDecl(dynamic_cast<VarDecl*>(child));
			}
			else if (x->statement->TypeMatches<IfStatement>()) {
                return ConvertIfStatement(dynamic_cast<IfStatement*>(child));			
			}
			else if (x->statement->TypeMatches<WhileStatement>()) {
                return ConvertWhileStatement(dynamic_cast<WhileStatement*>(child));
			}
			else if (x->statement->TypeMatches<ReturnStatement>()) {
                return ConvertReturnStatement(dynamic_cast<ReturnStatement*>(child));
			}
			else if (x->statement->TypeMatches<ExprStatement>()) {
                return ConvertExprStatement(dynamic_cast<ExprStatement*>(child));
			}
			else if (x->statement->TypeMatches<Function>()) {
                return ConvertFunction(dynamic_cast<Function*>(child));
			}
			else if (x->statement->TypeMatches<ImportStatement>()) { 
				return ConvertImportStatement(dynamic_cast<ImportStatement*>(child));
			}
			else {
                Error("Unrecognized statement type: " + x->ToString());
				return NULL;
			}
        }

		lls::Seq* ConvertCodeBlock(NonNull<CodeBlock> x) {
			lls::Seq* r = new lls::Seq();
			for (int i=0; i < x->statements.Count(); ++i) {
				r->AddChild(ConvertStatement(x->statements.At(i)));
			}
			return r;
        }

		lls::Name* ConvertName(NonNull<Name> x) {
			lls::Name* r = new lls::Name(x->ToString());
			return r;
		}

		lls::Type* ConvertType(TypeExpr* x) {
			if (x == NULL) 
				return new lls::Type("Object");
            else if (StringBeginsWith(x->ToString(), "Array")) 
				return new lls::Type("List");
            else 
				return new lls::Type(x->ToString());
		}

		lls::Formal* ConvertFormal(NonNull<Arg> x) {
			lls::Formal* r = new lls::Formal();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertType(x->type));
			return r;
		}

		lls::Formals* ConvertFormals(NonNull<ArgList> x) {
			lls::Formals* r = new lls::Formals(); 
			for (int i=0; i < x->args.Count(); ++i) {
				r->AddChild(ConvertFormal(x->args.At(i)));
            }
			return r;
		}

		lls::Define* ConvertFunction(NonNull<Function> x) {			
			lls::Define* r = new lls::Define();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertFormals(x->args));
			r->AddChild(ConvertType(x->type));
            r->AddChild(ConvertCodeBlock(x->body));
			return r;
        }

		lls::Inherits* ConvertInherits(Inherits* x) {
			lls::Inherits* r = new lls::Inherits();
			if (x == NULL) 
				return r;
			for (int i=0; i < x->types.Count(); ++i)
				r->AddChild(ConvertType(x->types.At(i)));
			return r;
		}

		lls::Implements* ConvertImplements(Implements* x) {
			lls::Implements* r = new lls::Implements();
			if (x == NULL) 
				return r;
			for (int i=0; i < x->types.Count(); ++i)
				r->AddChild(ConvertType(x->types.At(i)));
			return r;
		}

		lls::Method* ConvertMethod(NonNull<Method> x) {
			lls::Method* r = new lls::Method();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertFormals(x->args));
			r->AddChild(ConvertType(x->type));
			if (x->body == NULL)
				r->AddChild(new lls::Seq()); else
				r->AddChild(ConvertCodeBlock(x->body));
			return r;
		}

		lls::Methods* ConvertMethods(Methods* x) {
			lls::Methods* r = new lls::Methods();
			if (x == NULL) 
				return r;
			for (int i=0; i < x->methods.Count(); ++i)
				r->AddChild(ConvertMethod(x->methods.At(i)));
			return r;
		}

		lls::Field* ConvertField(NonNull<Field> x) {
			lls::Field* r = new lls::Field();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertType(x->type));
			return r;
		}

		lls::Fields* ConvertFields(Fields* x) {
			lls::Fields* r = new lls::Fields();
			if (x == NULL) 
				return r;
			for (int i=0; i < x->fields.Count(); ++i)
				r->AddChild(ConvertField(x->fields.At(i)));
			return r;
		}

		lls::Class* ConvertClass(NonNull<Class> x) {
			lls::Class* r = new lls::Class();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertInherits(x->inherits));
			r->AddChild(ConvertImplements(x->implements));
			r->AddChild(ConvertMethods(x->methods));
			r->AddChild(ConvertFields(x->fields));
			return r;
		}

		SExpr* ConvertModule(NonNull<Module> x) {
			lls::Module* r = new lls::Module();
			r->AddChild(ConvertName(x->name));
			for (int i=0; i < x->classes.Count(); ++i) 
				r->AddChild(ConvertClass(x->classes.At(i)));
			return r;
		}

		SExpr* ConvertProgram(NonNull<Program> x) {
			lls::Program* r = new lls::Program();
			r->AddChild(ConvertName(x->name));
			r->AddChild(ConvertCodeBlock(x->block));
			return r;
		}

		SExpr* ConvertFile(NonNull<HeronFile> x) {			
			if (dynamic_cast<Program*>(x->program_or_module)) {
				return ConvertProgram(dynamic_cast<Program*>(x->program_or_module));
			}
			else if (dynamic_cast<Module*>(x->program_or_module)) {
 				return ConvertModule(dynamic_cast<Module*>(x->program_or_module));
			}
			else {
				Error("Internal error, malformed script file");
				return NULL;
			}
        }
    };

	lls::Module* Convert(NonNull<HeronFile> file) {
        HeronToLLS converter;
		SExpr* tmp = converter.ConvertFile(file);
		Assert(tmp->Is<lls::Module>());
		lls::Module* r = tmp->As<lls::Module>();
		heron_to_lls_pp::PostProcess(r);
		return r;
    }
}


#endif 
